package com.mugui.base.client.net.baghandle;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import cn.hutool.core.util.StrUtil;
import com.mugui.base.client.net.bagsend.WsOutTimeTask;
import com.mugui.sql.SqlServer;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.mugui.Mugui;
import com.mugui.base.base.ApplicationContext;
import com.mugui.base.base.Autowired;
import com.mugui.base.base.Component;
import com.mugui.base.client.net.bagsend.NetCall;
import com.mugui.base.client.net.bagsend.WSUtil;
import com.mugui.base.client.net.base.Cache;
import com.mugui.base.client.net.base.Filter;
import com.mugui.base.client.net.base.Listener;
import com.mugui.base.client.net.base.ModelInterface;
import com.mugui.base.client.net.bean.Message;
import com.mugui.base.client.net.bean.NetBag;
import com.mugui.base.client.net.cache.CacheModel;
import com.mugui.base.client.net.classutil.DataSave;
import com.mugui.base.client.net.filter.FilterModel;
import com.mugui.base.client.net.listener.ListenerModel;
import com.mugui.base.util.Other;

import cn.hutool.cache.impl.TimedCache;

@Component
public class NetHandle {

    @Autowired
    private NetBagModuleManager ModuleMessage = null;
    private final byte[] lock = new byte[0];

    public String httpHandle(NetBag bag, NetCall netCall) {
        if (System.getProperties().get("system_lock") == null) {
            synchronized (lock) {
                while (System.getProperties().get("system_lock") == null) {
                    System.out.println("等待！！！！！！！！");
                    Other.sleep(200);
                }
            }
        }

        NetBag tempbag;
        try {
            netBagLocal.set(bag);
            tempbag = resolveNetBag(bag, netCall);
            netBagLocal.remove();
            if (tempbag == null)
                throw new RuntimeException(bag + "");
            tempbag.setRet_data(null);
            tempbag.setHost(null);
            tempbag.setPort(null);
            tempbag.setFrom_host(null);
            tempbag.setFrom_port(null);
            tempbag.setTimestamp(null).setServer_type(null);
            return tempbag.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Autowired
    private WsOutTimeTask wsOutTimeTask;


    public String WsHandle(NetBag bag) {
        if (System.getProperties().get("system_lock") == null) {
            synchronized (lock) {
                while (System.getProperties().get("system_lock") == null) {
                    System.out.println("等待！！！！！！！！");
                    Other.sleep(200);
                }
            }
        }
        try {
            bag.setType(NetBag.TYPE_WS);
            String[] split = bag.getSession().split("[|]");
            if (split.length > 1) {
                String pong = split[split.length - 1];
                if (StrUtil.equalsIgnoreCase("pong", pong)) {
                    //ws 的pong 消息
                    return null;
                }
            }
            NetCall wsNetCall =WSUtil.unsubNetCall(bag.getSession());
            if (wsNetCall == null) {
                return null;
            }
            netBagLocal.set(bag);
            wsOutTimeTask.del(wsNetCall);
            String threadName = wsNetCall.getThreadName();
            if (threadName != null) {
                Thread.currentThread().setName(threadName);
            }
            System.out.println("WsHandle:" + bag);
            bag = resolveNetBag(bag, wsNetCall);
            netBagLocal.remove();
            if (bag == null) {
                return null;
            }

            bag.setRet_data(null);
            bag.setHost(null);
            bag.setPort(0);
            bag.setFrom_host(null);
            bag.setFrom_port(0);
            bag.setTimestamp(null).setServer_type(null);
            return bag.toString();

        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            try {
                SqlServer.reback();
            } catch (Throwable e) {
            }
        }
        return null;
    }

    private static final TimedCache<String, byte[]> HASH_MAP_CACHE = new TimedCache<>(60000 * 60 * 2);

    static {
        HASH_MAP_CACHE.schedulePrune(60000);
    }

    public static final ThreadLocal<NetBag> netBagLocal = new ThreadLocal<>();

    /**
     * 解析NetBag 到相应的处理位置
     *
     * @throws Exception
     */
    public NetBag resolveNetBag(NetBag bag, NetCall netCall) throws Exception {
        init();
        if (bag == null) {
            bag = new NetBag();
        }
        if (StringUtils.isBlank(bag.getFunc())
                || StringUtils.isBlank(bag.getHash())) {
            bag.setCode(503);
            bag.setData(Message.error("参数错误"));
            return bag;
        }

        String server_name = bag.getServer_type();
        if (server_name == null) {

            if (StringUtils.isBlank("")) {
                server_name = "default";
            }
            bag.setServer_type(server_name);
        }
        String key = bag.getSession() + ":" + bag.getHash();
        synchronized (HASH_MAP_CACHE) {
            byte[] bs = HASH_MAP_CACHE.get(key, false);
            if (bs != null) {
                bag.setCode(503);
                bag.setData(Message.error("消息回环"));
                return bag;
            }
            HASH_MAP_CACHE.put(key, new byte[0]);

        }

        // 分布式消息
        NetBag handleAddForward = handleAddForward(bag);
        if (handleAddForward != null) {
            handleAddForward.setRet_data(null);
            return handleAddForward;
        }
        Message data = null;
        try {
            // 过滤器
            NetBag handleAddFilter = handleAddFilter(bag);
            if (handleAddFilter != null) {
                handleAddFilter.setRet_data(null);
                return handleAddFilter;
            }

            NetBag handleAddCache = handleAddCache(bag);
            if (handleAddCache != null) {
                return handleAddCache;
            }

            if (netCall != null && netCall.isCall()) {
                if (!(bag.getData() instanceof JSONObject) && !(bag.getData() instanceof Message)) {
                    bag.setRet_data(null);
                    return bag;
                }
                Message message = Message.newBean(Message.class, bag.getData());
                NetCall.Call son = netCall.getSon();
                if (son != null) {
                    if (message.getType() == Message.SUCCESS) {
                        message = son.ok(message);
                    } else {
                        message = son.err(message);
                    }
                }
                NetCall.Call main = netCall.getMain();
                if (main != null) {
//					MessageRunnable messageRunnable = new MessageRunnable(main, message);
////					handler.post(messageRunnable);
//					message = messageRunnable.call();
                    if (message.getType() == Message.SUCCESS) {
                        message = main.ok(message);
                    } else {
                        message = main.err(message);
                    }
                }
                data = message;
            } else {
                ModelInterface modelInterface = ModuleMessage
                        .get(bag.getFunc().substring(0, bag.getFunc().lastIndexOf(".")));
                if (modelInterface == null) {
                    modelInterface = ModuleMessage.get(bag.getFunc());
                }
                if (modelInterface == null) {
                    bag.setCode(503);
                    bag.setData(Message.error("参数错误" + bag.getFunc()));
                    return bag;
                }
                data = (Message) modelInterface.invokeFunction("runFunc", bag);
            }
            saveCache(data, bag);
            bag.setCode(200);
            bag.setData(data);
            return bag;
        } catch (Exception e) {
            e.printStackTrace();

            bag.setCode(503);
            bag.setData(Message.error("数据传输错误"));
            return bag;
        } finally {
            handleAddListener(bag, data);
        }
    }

    public void pong(String message) {

    }

    private class MessageRunnable implements Runnable {
        NetCall.Call main;
        Message message;

        public MessageRunnable(NetCall.Call main, Message message) {
            this.main = main;
            this.message = message;
        }

        @Override
        public void run() {
            if (message.getType() == Message.SUCCESS) {
                ret_msg = main.ok(message);
            } else {
                ret_msg = main.err(message);
            }
            synchronized (this) {
                this.notifyAll();
            }
        }

        Message ret_msg = null;

        public Message call() {
            if (ret_msg == null) {
                synchronized (this) {
                    try {
                        if (ret_msg == null) {
                            this.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            return ret_msg;
        }
    }

    Mugui object = null;

    private NetBagModuleManager manager = null;
    private ApplicationContext applicationContext = null;
//	private Handler handler = null;

    public void init() {
        if (applicationContext == null)
            applicationContext = (ApplicationContext) DataSave.context;
        if (applicationContext != null) {
            manager = applicationContext.getBean(NetBagModuleManager.class);
        }
//		if (handler == null) {
//			handler = new Handler(DataSave.app.getApplicationContext().getMainLooper());
//		}
        if (manager == null) {
            throw new RuntimeException("启动错误：" + NetBagModuleManager.class + " 未初始化");
        }
    }

    private static final String MATCH_STR = "[a-z A-Z 0-9 . _]*";

    private boolean handleFilterModel(String string, FilterModel filterModel) {
        Filter filter = filterModel.getClass().getAnnotation(Filter.class);
        String values[] = filter.value();
        boolean b = filter.type() == Filter.POSITIVE ? false : true;
        for (String value : values) {
            boolean bool = string.matches(value.replaceAll("[*]", MATCH_STR));
            switch (filter.type()) {
                case Filter.POSITIVE:
                    if (bool) {
                        return true;
                    }
                    break;
                case Filter.REVERSE:
                    if (bool) {
                        return false;
                    }
                    break;
            }
        }
        return b;
    }

    private boolean handleListenerModel(String string, ListenerModel listenerModel) {
        Listener listener = listenerModel.getClass().getAnnotation(Listener.class);
        String values[] = listener.value();
        boolean b = listener.type() == Listener.POSITIVE ? false : true;
        for (String value : values) {
            boolean bool = string.matches(value.replaceAll("[*]", MATCH_STR));
            switch (listener.type()) {
                case Listener.POSITIVE:
                    if (bool) {
                        return true;
                    }
                    break;
                case Listener.REVERSE:
                    if (bool) {
                        return false;
                    }
                    break;
            }
        }
        return b;
    }

    private boolean handleCacheModel(String string, CacheModel cacheModel) {
        Cache listener = cacheModel.getClass().getAnnotation(Cache.class);
        String values[] = listener.value();
        boolean b = listener.type() == Cache.POSITIVE ? false : true;
        for (String value : values) {
            boolean bool = string.matches(value.replaceAll("[*]", MATCH_STR));
            switch (listener.type()) {
                case Cache.POSITIVE:
                    if (bool) {
                        return true;
                    }
                    break;
                case Cache.REVERSE:
                    if (bool) {
                        return false;
                    }
                    break;
            }
        }
        return b;
    }

    private HashMap<String, List<FilterModel>> filterMap = new HashMap<>();
    private HashMap<String, List<ListenerModel>> listenerMap = new HashMap<>();
    private HashMap<String, List<CacheModel>> cacheMap = new HashMap<>();

    /**
     * 消息结果监听器
     *
     * @param bag
     * @param data
     * @auther 木鬼
     */
    private void handleAddListener(NetBag bag, Message data) {
        List<ListenerModel> listenerModels = null;
        if ((listenerModels = listenerMap.get(bag.getFunc())) == null) {
            synchronized (listenerMap) {
                if ((listenerModels = listenerMap.get(bag.getFunc())) == null) {
                    listenerMap.put(bag.getFunc(), listenerModels = new LinkedList<>());
                    if (manager.getListenerMessage() != null) {
                        Iterator<Map.Entry<String, ListenerModel>> iterator = manager.getListenerMessage().entrySet()
                                .iterator();
                        while (iterator.hasNext()) {
                            Map.Entry<String, ListenerModel> entry = iterator.next();
                            String string = bag.getFunc();
                            boolean bool = handleListenerModel(string, entry.getValue());
                            if (bool) {
                                listenerModels.add(entry.getValue());
                            }
                        }
                        Collections.sort(listenerModels, new Comparator<ListenerModel>() {
                            @Override
                            public int compare(ListenerModel o1, ListenerModel o2) {
                                Listener filter1 = o1.getClass().getAnnotation(Listener.class);
                                Listener filter2 = o2.getClass().getAnnotation(Listener.class);
                                return filter1.weight() - filter2.weight();
                            }
                        });
                    }
                }
            }
        }
        for (ListenerModel model : listenerModels) {
            try {

                model.listener((Message) data, bag);
            } catch (Exception e) {
                e.printStackTrace();

            }
        }
    }

    private void saveCache(Message data, NetBag bag) {
        List<CacheModel> cacheModels = cacheLocal.get();
        if (cacheModels == null) return;
        for (CacheModel model : cacheModels) {
            try {

                model.save(data, bag);
            } catch (Exception e) {
                e.printStackTrace();

            }
        }
        cacheLocal.remove();
    }

    private ThreadLocal<List<CacheModel>> cacheLocal = new ThreadLocal<>();

    /**
     * 缓存区
     *
     * @param bag
     * @return
     * @auther 木鬼
     */
    private NetBag handleAddCache(NetBag bag) {
        List<CacheModel> cacheModels = null;
        if ((cacheModels = cacheMap.get(bag.getFunc())) == null) {
            synchronized (cacheMap) {
                if ((cacheModels = cacheMap.get(bag.getFunc())) == null) {
                    cacheMap.put(bag.getFunc(), cacheModels = new LinkedList<>());
                    if (manager.getCacheMessage() != null) {
                        Iterator<Map.Entry<String, CacheModel>> iterator = manager.getCacheMessage().entrySet()
                                .iterator();
                        while (iterator.hasNext()) {
                            Map.Entry<String, CacheModel> entry = iterator.next();
                            String string = bag.getFunc();
                            boolean bool = handleCacheModel(string, entry.getValue());
                            if (bool) {
                                cacheModels.add(entry.getValue());
                            }
                        }
                    }
                }
            }
        }
        cacheLocal.set(cacheModels);
        for (CacheModel model : cacheModels) {
            try {
                if (model.load(bag) == null) {
                    return bag;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * 处理过滤器
     *
     * @param bag
     * @return
     * @auther 木鬼
     */

    private NetBag handleAddFilter(NetBag bag) {
        List<FilterModel> filterModels = null;
        if ((filterModels = filterMap.get(bag.getFunc())) == null) {
            synchronized (filterMap) {
                if ((filterModels = filterMap.get(bag.getFunc())) == null) {
                    filterMap.put(bag.getFunc(), filterModels = new LinkedList<>());
                    if (manager.getFilterMessage() != null) {
                        Iterator<Map.Entry<String, FilterModel>> iterator = manager.getFilterMessage().entrySet()
                                .iterator();
                        while (iterator.hasNext()) {
                            Map.Entry<String, FilterModel> entry = iterator.next();
                            String string = bag.getFunc();
                            boolean bool = handleFilterModel(string, entry.getValue());
                            if (bool) {
                                filterModels.add(entry.getValue());
                            }
                        }
                        Collections.sort(filterModels, new Comparator<FilterModel>() {
                            @Override
                            public int compare(FilterModel o1, FilterModel o2) {
                                Filter filter1 = o1.getClass().getAnnotation(Filter.class);
                                Filter filter2 = o2.getClass().getAnnotation(Filter.class);
                                return filter2.weight() - filter1.weight();
                            }
                        });
                    }
                }
            }

        }

        for (FilterModel model : filterModels) {
            try {
                if (model.filter(bag) == null) {
                    return bag;
                }
            } catch (Exception e) {
                e.printStackTrace();

            }

        }
        return null;
    }

    private NetBag handleAddForward(NetBag bag) {

        String func[] = bag.getFunc().split("[.]");
        if (bag.getFunc().startsWith("&forward.insert.")) {
            Message message = null;
            try {
                message = (Message) object.invokeFunction(func[func.length - 1], bag);
            } catch (Exception e) {
                message.setDate(e.getMessage());
            }
            bag.setCode(200);
            bag.setData(message);
            return bag;
        }
        return null;
    }

}
